/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * Copyright (C) 2016-2020 the ohosAnnotations project
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.internal.helper;

import com.alibaba.fastjson.JSONObject;

import org.ohosannotations.OhosAnnotationsEnvironment;
import org.ohosannotations.Option;
import org.ohosannotations.helper.OhosManifest;
import org.ohosannotations.internal.exception.OhosManifestNotFoundException;
import org.ohosannotations.internal.helper.entity.ConfigEntity;
import org.ohosannotations.logger.Logger;
import org.ohosannotations.logger.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.lang.model.util.Elements;

import static org.ohosannotations.helper.CaseHelper.upperCaseFirst;
import static org.ohosannotations.helper.ModelConstants.classSuffix;

/**
 * OhosManifestFinder
 *
 * @author dev
 * @since 2021-07-21
 */
public class OhosManifestFinder {
    /**
     * 选项清单
     */
    public static final Option OPTION_MANIFEST
        = new Option("ohosConfigFile", null);

    /**
     * 选择库
     */
    public static final Option OPTION_LIBRARY = new Option("library", "false");
    /**
     * 选择即时搜索功能
     */
    public static final Option OPTION_INSTANT_FEATURE = new Option("instantAppFeature", "false");

    /**
     * 日志记录器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(OhosManifestFinder.class);

    /**
     * 环境
     */
    private final OhosAnnotationsEnvironment environment;

    /**
     * OhosManifestFinder
     *
     * @param environment 环境
     */
    public OhosManifestFinder(OhosAnnotationsEnvironment environment) {
        this.environment = environment;
    }

    /**
     * extractOhosManifest
     *
     * @return {@link OhosManifest}
     * @throws OhosManifestNotFoundException 清单没有发现异常
     */
    public OhosManifest extractOhosManifest() throws OhosManifestNotFoundException {
        try {
            File ohosManifestFile = findManifestFile();
            String projectDirectory = ohosManifestFile.getParent();

            boolean libraryOption = environment.getOptionBooleanValue(OPTION_LIBRARY);

            if (libraryOption) {
                return parse(ohosManifestFile, true);
            }

            File projectProperties = new File(projectDirectory, "project.properties");

            boolean libraryProject;
            libraryProject = isLibraryProject(projectProperties, false);

            return parse(ohosManifestFile, libraryProject);
        } catch (FileNotFoundException exception) {
            throw new OhosManifestNotFoundException("Unable to find ohosConfig.json", exception);
        }
    }

    private boolean isLibraryProject(File projectProperties, boolean libraryProject) {
        if (projectProperties.exists()) {
            Properties properties = new Properties();
            try {
                properties.load(new FileInputStream(projectProperties));
                if (properties.containsKey("ohos.library")) {
                    String ohosLibraryProperty = properties.getProperty("ohos.library");
                    libraryProject = "true".equals(ohosLibraryProperty);

                    LOGGER.debug("Found ohos.library={} property in project.properties", libraryProject);
                }
            } catch (IOException ignored) {
                // we assume the project is not a library
            }
        }
        return libraryProject;
    }

    /**
     * 找到清单文件
     *
     * @return {@link File}
     * @throws FileNotFoundException 文件未发现异常
     */
    private File findManifestFile() throws FileNotFoundException {
        String ohosManifestFile = environment.getOptionValue(OPTION_MANIFEST);
        if (ohosManifestFile != null) {
            return findManifestInSpecifiedPath(ohosManifestFile);
        } else {
            return findManifestInKnownPaths();
        }
    }

    /**
     * 在指定路径中找到清单
     *
     * @param ohosConfigPath 嗳哟配置路径
     * @return {@link File}
     * @throws FileNotFoundException 文件未发现异常
     */
    private File findManifestInSpecifiedPath(String ohosConfigPath) throws FileNotFoundException {
        File ohosConfigFile = new File(ohosConfigPath);
        if (!ohosConfigFile.exists()) {
            LOGGER.error("Could not find the ohosConfig.json file in specified path : {}", ohosConfigPath);
            throw new FileNotFoundException();
        } else {
            LOGGER.debug("ohosConfig.json file found with specified path: {}", ohosConfigFile.toString());
        }
        return ohosConfigFile;
    }

    /**
     * 在已知路径找到清单
     *
     * @return {@link File}
     * @throws FileNotFoundException 文件未发现异常
     */
    private File findManifestInKnownPaths() throws FileNotFoundException {
        FileHelper.FileHolder holder = FileHelper.findRootProjectHolder(environment.getProcessingEnvironment());
        return findManifestInKnownPathsStartingFromGenFolder(holder.sourcesGenerationFolder.getAbsolutePath());
    }

    /**
     * 在已知路径从创文件夹找到清单
     *
     * @param sourcesGenerationFolder 源生成的文件夹
     * @return {@link File}
     */
    File findManifestInKnownPathsStartingFromGenFolder(String sourcesGenerationFolder) {
        Iterable<OhosManifestFinderStrategy> strategies = Arrays
            .asList(new GradleOhosManifestFinderStrategy(environment, sourcesGenerationFolder),
                new LegacyGradleOhosManifestFinderStrategy(environment, sourcesGenerationFolder),
                new MavenOhosManifestFinderStrategy(sourcesGenerationFolder),
                new EclipseOhosManifestFinderStrategy(sourcesGenerationFolder));

        OhosManifestFinderStrategy applyingStrategy = null;

        for (OhosManifestFinderStrategy strategy : strategies) {
            if (strategy.applies()) {
                applyingStrategy = strategy;
                break;
            }
        }

        File ohosConfigFile = null;

        if (applyingStrategy != null) {
            ohosConfigFile = applyingStrategy.findOhosConfigFile();
        }

        if (ohosConfigFile != null) {
            LOGGER.debug("{} ohosConfig.json file found using generation" +
                " folder {}: {}", applyingStrategy.name, sourcesGenerationFolder, ohosConfigFile.toString());
        } else {
            LOGGER.error("Could not find the ohosConfig.json file, " +
                "using  generation folder [{}])", sourcesGenerationFolder);
        }
        return ohosConfigFile;
    }

    /**
     * 清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static abstract class OhosManifestFinderStrategy {
        final String name;

        final Matcher matcher;

        OhosManifestFinderStrategy(String name, Pattern sourceFolderPattern, String sourceFolder) {
            this.name = name;
            this.matcher = sourceFolderPattern.matcher(sourceFolder);
        }

        File findOhosConfigFile() {
            for (String location : possibleLocations()) {
                File manifestFile = new File(matcher.group(1), location + "/config.json");
                if (manifestFile.exists()) {
                    return manifestFile;
                }
            }
            return null;
        }

        boolean applies() {
            return matcher.matches();
        }

        abstract Iterable<String> possibleLocations();
    }

    /**
     * gradle嗳哟清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static class GradleOhosManifestFinderStrategy extends AbstractGradleOhosManifestFinderStrategy {
        private static final Pattern GRADLE_GEN_FOLDER
            = Pattern.compile("^(.*?)build[\\\\/]generated[\\\\/]source[\\\\/]annotation[\\\\/](.*)$");

        GradleOhosManifestFinderStrategy(OhosAnnotationsEnvironment environment, String sourceFolder) {
            super(GRADLE_GEN_FOLDER, environment, sourceFolder);
        }

        @Override
        protected String getGradleVariant() {
            return matcher.group(2);
        }
    }

    /**
     * 遗留gradle嗳哟清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static class LegacyGradleOhosManifestFinderStrategy
        extends AbstractGradleOhosManifestFinderStrategy {
        private static final Pattern GRADLE_GEN_FOLDER
            = Pattern.compile("^(.*?)build[\\\\/]generated[\\\\/]source[\\\\/](k?apt)(.*)$");

        LegacyGradleOhosManifestFinderStrategy(OhosAnnotationsEnvironment environment, String sourceFolder) {
            super(GRADLE_GEN_FOLDER, environment, sourceFolder);
        }

        @Override
        protected String getGradleVariant() {
            return matcher.group(3).substring(1);
        }
    }

    /**
     * 文摘gradle清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static abstract class AbstractGradleOhosManifestFinderStrategy
        extends OhosManifestFinderStrategy {
        static final Pattern OUTPUT_JSON_PATTERN = Pattern.compile(".*,\"path\":\"(.*?)\",.*");

        private static final List<String> SUPPORTED_ABI_SPLITS
            = Arrays.asList("arm64-v8a", "armeabi", "armeabi-v7a", "mips", "mips64", "x86", "x86_64");
        private static final List<String> SUPPORTED_DENSITY_SPLITS
            = Arrays.asList("hdpi", "ldpi", "mdpi", "xhdpi", "xxhdpi", "xxxhdpi");

        private static final String BUILD_TOOLS_V32_MANIFEST_PATH = "build/intermediates/merge_profile";

        private final OhosAnnotationsEnvironment environment;

        /**
         * AbstractGradleOhosManifestFinderStrategy
         *
         * @param pattern pattern
         * @param environment environment
         * @param sourceFolder sourceFolder
         */
        AbstractGradleOhosManifestFinderStrategy(Pattern pattern,
            OhosAnnotationsEnvironment environment, String sourceFolder) {
            super("Gradle", pattern, sourceFolder);
            this.environment = environment;
        }

        /**
         * 获取路径
         *
         * @return {@link String}
         */
        protected String getPath() {
            return matcher.group(1);
        }

        /**
         * 得到gradle变体
         *
         * @return {@link String}
         */
        protected abstract String getGradleVariant();

        @Override
        Iterable<String> possibleLocations() {
            String path = getPath();
            String gradleVariant = getGradleVariant();

            List<String> possibleLocations = new ArrayList<>();
            findPossibleLocationsV32(path, gradleVariant, possibleLocations);
            for (String directory : Arrays.asList("build/intermediates/manifests/full",
                "build/intermediates/bundles", "build/intermediates/manifests/aapt",
                "build/intermediates/library_manifest")) {
                findPossibleLocations(path, directory, gradleVariant, possibleLocations);
            }

            return updateLocations(path, possibleLocations);
        }

        private List<String> updateLocations(String path, List<String> possibleLocations) {
            List<String> knownLocations = new ArrayList<>();
            for (String location : possibleLocations) {
                String expectedLocation = path + "/" + location;
                File file = new File(expectedLocation + "/output.json");
                if (file.exists()) {
                    Matcher jsonMatcher = OUTPUT_JSON_PATTERN.matcher(readJsonFromFile(file));
                    if (jsonMatcher.matches()) {
                        String relativeManifestPath = jsonMatcher.group(1);
                        File manifestFile = new File(expectedLocation + "/" + relativeManifestPath);
                        String manifestDirectory = "";
                        try {
                            manifestDirectory = manifestFile.getParentFile().getCanonicalPath();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        knownLocations.add(manifestDirectory.substring(path.length()));
                    }
                }
            }

            if (knownLocations.isEmpty()) {
                knownLocations.addAll(possibleLocations);
            }

            return knownLocations;
        }

        private String readJsonFromFile(File file) {
            try (BufferedReader fileReader = new BufferedReader(new FileReader(file))) {
                return fileReader.readLine();
            } catch (IOException e) {
                LOGGER.error(e, "unable to read json file: {}", file);
                return "";
            }
        }

        private void findPossibleLocationsV32(String basePath,
            String variantPart, List<String> possibleLocations) {
            String[] directories = new File(basePath + BUILD_TOOLS_V32_MANIFEST_PATH).list();

            if (directories == null) {
                return;
            }

            if (variantPart.startsWith("/") || variantPart.startsWith("\\")) {
                variantPart = variantPart.substring(1);
            }

            boolean isFeature = environment.getOptionBooleanValue(OPTION_INSTANT_FEATURE)
                && (variantPart.startsWith("feature/") || variantPart.startsWith("feature\\"));
            if (isFeature) {
                variantPart = variantPart.substring(8);
            }

            String[] variantParts = variantPart.split("[/\\\\]");
            if (variantParts.length > 1) {
                StringBuilder sb = new StringBuilder(variantParts[0]);
                for (int i = 1; i < variantParts.length; i++) {
                    String part = variantParts[i];
                    sb.append(upperCaseFirst(part));
                }
                variantPart = sb.toString();
            }

            String possibleLocation = BUILD_TOOLS_V32_MANIFEST_PATH + "/" + variantPart;
            if (isFeature) {
                variantPart += "Feature";
                possibleLocation += "Feature";
            }

            findPossibleLocations(basePath, possibleLocations, possibleLocation);
            findPossibleLocations(basePath, possibleLocations,
                possibleLocation
                    + "/process" + upperCaseFirst(variantPart) + "Manifest/merged");
        }

        private void findPossibleLocations(String basePath,
            List<String> possibleLocations, String possibleLocationWithProcessManifest) {
            if (new File(basePath, possibleLocationWithProcessManifest).isDirectory()) {
                possibleLocations.add(possibleLocationWithProcessManifest);
                addPossibleSplitLocations(basePath, possibleLocationWithProcessManifest, possibleLocations);
            }
        }

        private void findPossibleLocations(String basePath, String targetPath,
            String variantPart, List<String> possibleLocations) {
            String[] directories = new File(basePath + targetPath).list();

            if (directories == null) {
                return;
            }

            if (variantPart.startsWith("/") || variantPart.startsWith("\\")) {
                variantPart = variantPart.substring(1);
            }

            for (String directory : directories) {
                String possibleLocation = targetPath + "/" + directory;
                File variantDir = new File(basePath + possibleLocation);
                if (variantDir.isDirectory() && variantPart.toLowerCase(Locale.ENGLISH)
                    .startsWith(directory.toLowerCase(Locale.ENGLISH))) {
                    String remainingPart = variantPart.substring(directory.length());
                    if (remainingPart.length() == 0) {
                        possibleLocations.add(possibleLocation);
                        addPossibleSplitLocations(basePath, possibleLocation, possibleLocations);
                    } else {
                        findPossibleLocations(basePath, possibleLocation, remainingPart, possibleLocations);
                    }
                }
            }
        }

        private void addPossibleSplitLocations(String basePath,
            String possibleLocation, List<String> possibleLocations) {
            for (String abiSplit : SUPPORTED_ABI_SPLITS) {
                File splitDir = new File(basePath + possibleLocation + "/" + abiSplit);
                if (splitDir.isDirectory()) {
                    possibleLocations.add(possibleLocation + "/" + abiSplit);
                    for (String densitySplit : SUPPORTED_DENSITY_SPLITS) {
                        File splitSubDir = new File(basePath
                            + possibleLocation + "/" + abiSplit + "/" + densitySplit);
                        if (splitSubDir.isDirectory()) {
                            possibleLocations.add(possibleLocation + "/" + abiSplit + "/" + densitySplit);
                        }
                    }
                }
            }
            for (String densitySplit : SUPPORTED_DENSITY_SPLITS) {
                File splitDir = new File(basePath + possibleLocation + "/" + densitySplit);
                if (splitDir.isDirectory()) {
                    possibleLocations.add(possibleLocation + "/" + densitySplit);
                }
            }
        }
    }

    /**
     * maven清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static class MavenOhosManifestFinderStrategy extends OhosManifestFinderStrategy {
        static final Pattern MAVEN_GEN_FOLDER = Pattern.compile("^(.*?)target[\\\\/]generated-sources.*$");

        MavenOhosManifestFinderStrategy(String sourceFolder) {
            super("Maven", MAVEN_GEN_FOLDER, sourceFolder);
        }

        @Override
        Iterable<String> possibleLocations() {
            return Arrays.asList("target", "src/main", "");
        }
    }

    /**
     * eclipse清单搜索策略
     *
     * @author dev
     * @since 2021-07-23
     */
    private static class EclipseOhosManifestFinderStrategy extends OhosManifestFinderStrategy {
        static final Pattern ECLIPSE_GEN_FOLDER = Pattern.compile("^(.*?)\\.apt_generated.*$");

        EclipseOhosManifestFinderStrategy(String sourceFolder) {
            super("Eclipse", ECLIPSE_GEN_FOLDER, sourceFolder);
        }

        @Override
        Iterable<String> possibleLocations() {
            return Collections.singleton("");
        }
    }


    /**
     * file2字符串
     * file2String
     *
     * @param file file
     * @return String
     */
    public static String file2String(File file) {
        StringBuffer buffer = new StringBuffer();
        try {
            FileInputStream f1 = new FileInputStream(file);
            BufferedReader bis = new BufferedReader(new InputStreamReader(f1));
            String line = "";
            while ((line = bis.readLine()) != null) {
                buffer.append(line);
            }
            f1.close();
            bis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    /**
     * 解析
     *
     * @param ohosConfigFile Ohos配置文件
     * @param libraryProject 库项目
     * @return {@link OhosManifest}
     */
    private OhosManifest parse(File ohosConfigFile, boolean libraryProject) {
        String json = file2String(ohosConfigFile);
        ConfigEntity config = JSONObject.parseObject(json, ConfigEntity.class);

        if (config == null || config.app == null) {
            LOGGER.error("Could not parse the ohosConfig.json file at path {}", ohosConfigFile);
        }

        String applicationPackage = config.app.bundleName;
        int minSdkVersion = config.app.apiVersion.compatible;
        int maxSdkVersion = config.app.apiVersion.compatible;
        int targetSdkVersion = config.app.apiVersion.target;

        if (libraryProject) {
            return OhosManifest.createLibraryManifest(applicationPackage,
                minSdkVersion, maxSdkVersion, targetSdkVersion);
        }

        String applicationClassQualifiedName = null;
        boolean applicationDebuggableMode = false;

        String nameAttribute = config.module.name;
        applicationClassQualifiedName = manifestNameToValidQualifiedName(applicationPackage, nameAttribute);

        if (applicationClassQualifiedName == null) {
            LOGGER.warn("The class application declared in "
                    + "the ohosConfig.json cannot be found in the compile path: [{}]",
                nameAttribute);
        }

        List<ConfigEntity.ModuleBean.AbilitiesBean> abilityList = config.module.abilities;
        List<String> abilityQualifiedNames = extractComponentNames(applicationPackage, abilityList);

        List<String> componentQualifiedNames = new ArrayList<>();
        componentQualifiedNames.addAll(abilityQualifiedNames);

        ConfigEntity.ModuleBean.MetaDataBean metaDataNodes = config.module.metaData;
        Map<String, OhosManifest.MetaDataInfo> metaDataQualifiedNames
            = extractMetaDataQualifiedNames(metaDataNodes);

        List<ConfigEntity.ModuleBean.ReqPermissionsBean> usesPermissionNodes = config.module.reqPermissions;
        List<String> usesPermissionQualifiedNames = extractUsesPermissionNames(usesPermissionNodes);

        List<String> permissionQualifiedNames = new ArrayList<>();
        if (usesPermissionQualifiedNames != null) {
            permissionQualifiedNames.addAll(usesPermissionQualifiedNames);
        }

        return OhosManifest.createManifest(applicationPackage,
            applicationClassQualifiedName, componentQualifiedNames,
            metaDataQualifiedNames,
            permissionQualifiedNames, minSdkVersion,
            maxSdkVersion, targetSdkVersion, applicationDebuggableMode);
    }

    /**
     * 提取组件名称
     *
     * @param applicationPackage 应用程序包
     * @param componentNodes 组件的节点
     * @return {@link List<String>}
     */
    private List<String> extractComponentNames(String applicationPackage,
        List<ConfigEntity.ModuleBean.AbilitiesBean> componentNodes) {
        if (componentNodes == null) {
            return null;
        }
        List<String> componentQualifiedNames = new ArrayList<>();
        for (int i = 0; i < componentNodes.size(); i++) {
            ConfigEntity.ModuleBean.AbilitiesBean abilityNode = componentNodes.get(i);
            String nameAttribute = abilityNode.name;

            String qualifiedName = manifestNameToValidQualifiedName(applicationPackage, nameAttribute);

            if (qualifiedName != null) {
                componentQualifiedNames.add(qualifiedName);
            } else {
                if (nameAttribute != null) {
                    LOGGER.warn("A class ability declared in the ohosConfig" +
                            ".json cannot be found in the compile path: [{}]",
                        nameAttribute);
                } else {
                    LOGGER.warn("The {} ability node in the ohosConfig" +
                        ".json has no ohos:name attribute", i);
                }
            }
        }
        return componentQualifiedNames;
    }

    /**
     * 提取元数据限定名
     *
     * @param metaDataNodes 元数据节点
     * @return metaDataQualifiedNames
     */
    private Map<String, OhosManifest.MetaDataInfo> extractMetaDataQualifiedNames
    (ConfigEntity.ModuleBean.MetaDataBean metaDataNodes) {
        if (metaDataNodes == null) {
            return null;
        }
        List<ConfigEntity.ModuleBean.MetaDataBean.CustomizeData> list = metaDataNodes.customizeData;
        Map<String, OhosManifest.MetaDataInfo> metaDataQualifiedNames = new HashMap<String, OhosManifest.MetaDataInfo>();
        for (int i = 0; i < list.size(); i++) {
            ConfigEntity.ModuleBean.MetaDataBean.CustomizeData node = list.get(i);
            String name = node.name;
            String value = node.value;
            String resource = node.extra;

            if (name == null || (value == null && resource == null)) {
                LOGGER.warn("A malformed <meta-data> has been "
                    + "found in the manifest with name {}", name);
            }
            metaDataQualifiedNames.put(name, new OhosManifest.MetaDataInfo(name, value, resource));
        }

        return metaDataQualifiedNames;
    }

    /**
     * 清单名称有效限定名称
     *
     * @param applicationPackage 应用程序包
     * @param abilityName 能力的名字
     * @return {@link String}
     */
    private String manifestNameToValidQualifiedName(String applicationPackage, String abilityName) {
        if (abilityName.startsWith(applicationPackage)) {
            return returnClassIfExistsOrNull(abilityName);
        } else {
            if (abilityName.startsWith(".")) {
                return returnClassIfExistsOrNull(applicationPackage + abilityName);
            } else {
                if (classOrModelClassExists(abilityName)) {
                    return abilityName;
                } else {
                    return returnClassIfExistsOrNull(applicationPackage + "." + abilityName);
                }
            }
        }
    }

    /**
     * 类或模型类存在
     *
     * @param className 类名
     * @return boolean
     */
    private boolean classOrModelClassExists(String className) {
        Elements elementUtils = environment.getProcessingEnvironment().getElementUtils();

        if (className.endsWith(classSuffix())) {
            className = className.substring(0, className.length() - classSuffix().length());
        }
        return elementUtils.getTypeElement(className) != null;
    }

    /**
     * 返回类如果存在或null
     *
     * @param className 类名
     * @return {@link String}
     */
    private String returnClassIfExistsOrNull(String className) {
        if (classOrModelClassExists(className)) {
            return className;
        } else {
            return null;
        }
    }

    /**
     * 提取使用权限名称
     *
     * @param usesPermissionNodes 使用许可的节点
     * @return {@link List<String>}
     */
    private List<String> extractUsesPermissionNames(List<ConfigEntity.ModuleBean
        .ReqPermissionsBean> usesPermissionNodes) {
        if (usesPermissionNodes == null) {
            return null;
        }
        List<String> usesPermissionQualifiedNames = new ArrayList<>();
        for (int i = 0; i < usesPermissionNodes.size(); i++) {
            ConfigEntity.ModuleBean.ReqPermissionsBean usesPermissionNode = usesPermissionNodes.get(i);
            String nameAttribute = usesPermissionNode.name;

            if (nameAttribute == null) {
                return null;
            }
            usesPermissionQualifiedNames.add(nameAttribute);
        }
        return usesPermissionQualifiedNames;
    }
}
